package com.hzit.pay.center.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.hzit.pay.center.config.MqConfig;
import com.hzit.pay.center.config.PayCenterConfig;
import com.hzit.pay.center.customer.MyMessagePostProcessor;
import com.hzit.pay.center.model.MchInfo;
import com.hzit.pay.center.model.NoticeInfo;
import com.hzit.pay.center.model.PaySerialNoInfo;
import com.hzit.pay.center.service.*;
import com.pay.center.common.enums.PayStatusEnum;
import com.pay.center.common.req.PayCallBackData;
import com.pay.center.common.utils.PayDigestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.Map;

/***
 * 异步回调处理实现类
 */
@Service
public class NotifyServiceImpl implements INotifyService {


    private Logger logger = LoggerFactory.getLogger(NotifyServiceImpl.class);


    @Autowired
    private RestTemplate restTemplate;


    @Autowired
    private PayCenterConfig payCenterConfig;

    @Autowired
    private IPaySerialNoService paySerialNoService;

    @Autowired
    private IMchService mchService;

    @Autowired
    private INoticeService noticeService;

    @Autowired
    private INoticeRuleService noticeRuleService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private static final String WAIT_BUYER_PAY = "WAIT_BUYER_PAY";
    private static final String TRADE_SUCCESS = "TRADE_SUCCESS";

    private static final String TRADE_FINISHED = "TRADE_FINISHED";
    private static final String TRADE_CLOSED = "TRADE_CLOSED";
    private static final String SUCCESS = "success";


    @Override
    public String notifyCalBack(Map<String, String> params) {

        try {
            //2.0签名认证
            String paySerialNo = params.get("out_trade_no");
            if (StringUtils.isEmpty(paySerialNo)){
                //打印
                logger.info("支付宝返回的支付流水号为空");
                return "fail";
            }

            boolean flag = AlipaySignature.rsaCheckV1(params, payCenterConfig.getAlipayPubKey(),
                    payCenterConfig.getAlipayCharSet(), payCenterConfig.getAlipaySignType());
            if (!flag){
                logger.info("支付流水号：{}，验证签名失败：{}",paySerialNo,flag);
                return "fail";
            }

            //2.1判断商户支付流水号是否存在，金额是否一致，
            PaySerialNoInfo paySerialNoInfo = paySerialNoService.queryBySerialNo(paySerialNo);

            if (ObjectUtils.isEmpty(paySerialNoInfo)){

                logger.info("支付宝返回的支付流水号：{},不存在",paySerialNo);
                return "fail";
            }

            String totalAmount = params.get("total_amount"); //注意单位

            if (!paySerialNoInfo.getPayAmount().toString().equals(totalAmount)){

                logger.info("支付宝返回的支付流水号：{},金额不匹配：{}",paySerialNo,totalAmount);

                return "fail";
            }

            //2.3 校验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商户可能有多个 seller_id/seller_email）；

            String sellerId = params.get("seller_id");
            String sellerEmail = params.get("seller_email");

            //2选一
            if (!payCenterConfig.getAlipaySellerId().equals(sellerId)
                    && !payCenterConfig.getAlipaySellerEmail().equals(sellerEmail)){

                logger.info("支付宝返回的支付流水号：{},sellerId：{}或sellerEmail:{}不正确",paySerialNo,
                        sellerId,sellerEmail);

                return "fail";
            }

            String appId = params.get("app_id");

            if (!payCenterConfig.getAlipayAppId().equals(appId)){
                logger.info("支付宝返回的支付流水号：{},appId不匹配：{}",paySerialNo,appId);

                return "fail";
            }

            String tradeStatus = params.get("trade_status");

            // 数据库状态为。失败或者成功，不需要修改状态
            if (PayStatusEnum.FAIL.getCode().equals(paySerialNoInfo.getPayStatus())
                && PayStatusEnum.SUCCESS.getCode().equals(paySerialNoInfo.getPayStatus())){
                logger.info("支付宝返回的支付流水号：{},已经是成功或者失败：{}",paySerialNo,tradeStatus);
                return "fail";
            }

            //2. 更新数据库：支付流水表中的状态：
            PaySerialNoInfo record = new PaySerialNoInfo();
            Date nowDate = new Date();
            record.setId(paySerialNoInfo.getId());
            record.setUpdateTime(nowDate);
            record.setUpdateBy("system");
            if (!StringUtils.isEmpty(params.get("trade_no"))){
                record.setRespSerialNumber(params.get("trade_no"));
            }

            if(WAIT_BUYER_PAY.equals(tradeStatus)){
                //更新完 支付中
                record.setPayStatus(PayStatusEnum.PAYING.getCode());
                record.setPayDesc("交易创建，等待买家付款");
            }else if(TRADE_SUCCESS.equals(tradeStatus) || TRADE_FINISHED.equals(tradeStatus)){
                record.setPayStatus(PayStatusEnum.SUCCESS.getCode());
                record.setPayDesc("交易支付成功");

            }else if(TRADE_CLOSED.equals(tradeStatus)){
                record.setPayStatus(PayStatusEnum.FAIL.getCode());
                record.setPayDesc("交易失败");
            }

            paySerialNoService.updateSerialNoStatus(record);

            //支付成功立马发送通知业务系统啊, 业务系统同步返回succes，不需要再次通知

            String url = "http://127.0.0.1:8899/orderCenter/callBack";

            PayCallBackData payCallBackData = new PayCallBackData();

            MchInfo mchInfo = mchService.queryMchInfoById("1000"); //TODO


            payCallBackData.setMchId("1000"); //TODO
            payCallBackData.setOrderId(paySerialNoInfo.getOrderId());
            payCallBackData.setOrderId(paySerialNoInfo.getOrderId());
            payCallBackData.setPaySerialNo(paySerialNoInfo.getPaySerialNumber());
            payCallBackData.setPayChannel(paySerialNoInfo.getPayChannel());
            payCallBackData.setPayMethod(paySerialNoInfo.getPayMethod());
            payCallBackData.setPayStatus(paySerialNoInfo.getPayStatus());

            JSONObject jsonObject = (JSONObject)JSONObject.toJSON(payCallBackData);

            String sign = PayDigestUtil.getSign(jsonObject,mchInfo.getRespKey(),"sign","signType");
            payCallBackData.setSignType("MD5");
            payCallBackData.setSign(sign);

            //查询通知表，
           NoticeInfo noticeInfo = noticeService.queryBySerialNo(paySerialNoInfo.getPaySerialNumber());


           //分之一：如果数据库中没有通知记录，认为是第一次通知
           if (ObjectUtils.isEmpty(noticeInfo)){

               String result = restTemplate.postForObject(url,payCallBackData,String.class);


               if ("success".equalsIgnoreCase(result)){
                   //通知成功了， 第一次就创建成功记录
                   noticeService.createNotice("1000",paySerialNo,"1");
               }else{

                   noticeService.createNotice("1000",paySerialNo,"0");
                   //没有通知成功，进入队列，等待消费去通知
                   Long ttl = 6000l; //noticeRuleService.getTtl("6000"); //第一次
                   MessagePostProcessor messagePostProcessor = new MyMessagePostProcessor(ttl);

                   rabbitTemplate.convertAndSend(MqConfig.BUSINESS_EXCHANGE_NAME,"",payCallBackData,messagePostProcessor);
               }

               return "success";
           }

           //分支二：请求已经不是第一次了。

            //判断状态，0是通知中， 1和-1 成功和失败 不需要发通知
            if (!"0".equals(noticeInfo.getNotifyStatus())){

                return "success";
            }

            //判断通知次数，如果达到上限8次，就不需要通知
            Integer noticeCount = noticeInfo.getNotifyCount();
            if (noticeCount >=8){
                return "success";
            }

            //进入队列，等待消费去发送通知
            //设置消息的ttl
            Long ttl = noticeRuleService.getTtl(String.valueOf(noticeInfo.getNotifyCount()));
            MessagePostProcessor messagePostProcessor = new MyMessagePostProcessor(ttl);
            rabbitTemplate.convertAndSend(MqConfig.BUSINESS_EXCHANGE_NAME,"",payCallBackData,messagePostProcessor);
            return "success";

        } catch (AlipayApiException e) {
            logger.error("AlipayApiException",e);
            return "fail";
        }
    }

    public static void main(String[] args) {

        String sellerEmail = "xydskv8413@sandbox.com";

        if (!"2088102179213370".equals("2088102179213371")
               && (!"xydskv8413@sandbox.com".equals(sellerEmail))){

            System.out.println("222222222222222");


        }else {

            System.out.println("----------------");
        }

    }
}
